﻿/**

 * Copyright (c) 2015-2016, FastDev 刘强 (fastdev@163.com).

 *

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

using OF.DistributeService.Core.Client.Entity;
using OF.DistributeService.Core.Entity;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using OF.DistributeService.Core.Attribute;

namespace OF.DistributeService.Core.Common
{
    public class WebApiUtil
    {
        private static Type DateTimeType = typeof(DateTime);
        private static Type DecimalType = typeof(decimal);
        private static Type StringType = typeof(string);
        private static Type GuidType = typeof(Guid);
        private static Type NullableType = typeof(Nullable<>).GetGenericTypeDefinition();
        private static Type ByteArrayType = typeof(byte[]);
        private static Type TaskGenericType = typeof(Task<>).GetGenericTypeDefinition();

        public static T Get<T>(string url, List<CommonApiCallContextParam> paramArray, ApiContentFormat contentFormat)
        {
            return sendUrlRequest<T>("GET", url, paramArray, contentFormat);
        }

        public static T Delete<T>(string url, List<CommonApiCallContextParam> paramArray, ApiContentFormat contentFormat)
        {
            return sendUrlRequest<T>("DELETE", url, paramArray, contentFormat);
        }

        private static string GetEncodeParamValue(Type paramType, object obj)
        {
            if (obj == null)
            { 
                return null;
            }
            Type inNulableType = Util.GetParamTyeIfNullable(paramType);
            string objString = null;
            if (inNulableType.Equals(DateTimeType))
            {
                objString = ((DateTime)obj).ToString(Util.DateTimeFormat);
            }
            else
            {
                objString = obj.ToString();
            }
            return HttpUtility.UrlEncode(objString);
        }

        private static T sendUrlRequest<T>(string methodName, string url, List<CommonApiCallContextParam> paramArray, ApiContentFormat contentFormat)
        {
            string paramStr = string.Empty;
            if (paramArray != null && paramArray.Count > 0)
            {
                StringBuilder sbParam = new StringBuilder("?");
                for (int i1 = 0; i1 < paramArray.Count; i1++)
                {
                    if (i1 > 0)
                    {
                        sbParam.Append("&");
                    }
                    var item = paramArray[i1];
                    sbParam.AppendFormat("{0}={1}", item.ParamName, GetEncodeParamValue(item.ParamType, item.ParamValue));
                }
                paramStr = sbParam.ToString();
            }
            Type type = typeof(T);
            ContentFormatGetClientBase<T> client = null; 
            if (contentFormat == ApiContentFormat.JSON)
            {
                client = new JSONContentFormatGetClient<T>(methodName, url + paramStr);
            }
            else
            {
                client = new MSGPackContentFormatGetClient<T>(methodName, url + paramStr);
            }
            if (IsGenericTaskType(type))
            {
                return client.GetAsync(type.GetGenericArguments()[0]);
            }
            else
            {
                return client.Get();                
            }
        }

        public static T Post<T>(string url, List<CommonApiCallContextParam> paramArray, ApiContentFormat contentFormat)
        {
            return sendBodyStreamRequest<T>("POST", url, paramArray, contentFormat);
        }

        public static T Put<T>(string url, List<CommonApiCallContextParam> paramArray, ApiContentFormat contentFormat)
        {
            return sendBodyStreamRequest<T>("PUT", url, paramArray, contentFormat);
        }

        private static bool IsGenericTaskType(Type type)
        {
            return type.IsGenericType && type.GetGenericTypeDefinition().Equals(TaskGenericType);
        }

        public static T sendBodyStreamRequest<T>(string methodName, string url, List<CommonApiCallContextParam> paramArray, ApiContentFormat contentFormat)
        {
            object paramObjValue = null;
            Type paramType = null;
            if (paramArray != null)
            {
                if (paramArray.Count > 1)
                {
                    throw new NotSupportedException("Post method can not have more than one params!");
                }

                if (paramArray.Count == 1)
                {
                    var paramObj = paramArray[0];
                    paramType = paramObj.ParamType;
                    paramObjValue = paramObj.ParamValue;                    
                }
            }
            Type type = typeof(T);
            ContentFormatPostClientBase<T> client = null;
            if (contentFormat == ApiContentFormat.JSON)
            {
                client = new JSONContentFormatPostClient<T>(methodName, url, paramType, paramObjValue);
            }
            else
            {
                client = new MSGPackContentFormatPostClient<T>(methodName, url, paramType, paramObjValue);
            }
            if (IsGenericTaskType(type))
            {
                return client.PostAsync(type.GetGenericArguments()[0]);
            }
            else
            {
                return client.Post();
            }
        }
    }
}